const {safeJson}=require('../safeJson');
const {safeStringify}=require('../safeStringify');
const {getPromiseValue}=require('../getPromiseValue');
const get=require('lodash/get');
const set=require('lodash/set');

export class MemoryStorage{
    data={};
    get(key){
        return this.data[key];
    }
    set(key,data){
        return this.data[key]=data;
    }
    remove(key){
        return delete this.data[key];
    }
}

const _localStorage={
    get(key){
        return localStorage.getItem(key);
    },
    set(key,data){
        return localStorage.setItem(key,data);
    },
    remove(key){
        return localStorage.removeItem(key);
    },
};

class Storage{
    storage=null;
    autoJson=true;
    event=null;
    namespace='';
    getKey(key){
        return `${this.namespace}_${key}`;
    }
    get(key){
        const _key=this.getKey(key);
        return getPromiseValue(this.storage.get(_key))
            .then((data)=>{
                if(!this.autoJson){
                    return data;
                }
                return safeJson(data);
            });
    }
    set(key,data){
        let _data=data;
        if(this.autoJson){
            _data=safeStringify(data);
        }
        const _key=this.getKey(key);
        return getPromiseValue(this.storage.set(_key,_data))
            .then((rst)=>{
                this.event&&this.event.emit('change',{key,data});
                return rst;
            });
    }
    remove(key){
        return getPromiseValue(this.storage.remove(key))
            .then((rst)=>{
                this.event&&this.event.emit('remove',{key});
                return rst;
            });
    }
    getData(key,path,defVal){
        return this.get(key)
            .then((data)=>{
                return get(data,path,defVal);
            });
    }
    setData(key,path,val){
        return this.get(key)
            .then((config)=>{
                const _config=config||{};
                set(_config,path,val);
                return this.set(key,_config);
            });
    }
    setStorage(storage){
        this.storage=storage;
    }
    setEvent(event){
        this.event=event;
    }
    getNamespace(){
        return this.namespace;
    }
    setNamespace(namespace=''){
        this.namespace=namespace;
    }
}

export const genStorage=({
    storage,
    event=null,
    namespace=''
}={})=>{
    const rst=new Storage();
    rst.setStorage(storage);
    rst.setEvent(event);
    rst.setNamespace(namespace);
    return rst;
};

export const genMemoryStorage=(opt)=>{
    return genStorage({
        ...opt,
        storage:new MemoryStorage
    });
};

export const genLocalStorage=(opt)=>{
    return genStorage({
        ...opt,
        storage:_localStorage
    });
};
export default genStorage;